#coding=utf-8

import copy
from django.views.generic.simple import direct_to_template
from django.shortcuts import get_object_or_404, HttpResponseRedirect
from django.core.urlresolvers import reverse
from models import Rule, \
    Condition, AttachmentCondition, \
    DateCondition, AddressCondition, KeywordCondition, \
    ANrCondition, SizeCondition, ResentCondition
from choices import CONDITION_TYPES_D, \
    ATTACHMENT_C, DATE_C, FROM_C, KEYWORD_C, \
    ANR_C, SIZE_C, RESENT_C,  SUBJECT_C, TO_C, \
    ACTION_TYPES_D, \
    SUBJECT_R, EQ_O
from forms import RuleForm, \
    NewConditionForm, AttachmentConditionForm, KeywordConditionForm, \
    DateConditionForm, FromConditionForm, ToConditionForm,  \
    ANrConditionForm, SizeConditionForm, ResentConditionForm, \
    SubjectConditionForm

#===============================================================================
# ### show rules ###
#===============================================================================

def show_rules(request):
    '''View rules' list'''
    
    rules = Rule.objects.exclude(is_tmp=True).order_by('-priority')
    ctx_dict = { 'rules': rules, 'no_options': True }
    conds_dict = CONDITION_TYPES_D
    actions_dict = ACTION_TYPES_D
    return direct_to_template (request, 'rules.html', 
                               dict(ctx_dict.items() + conds_dict.items() + actions_dict.items()))

def show_rule(request, ruleid):
    '''Show rule (conditions and action) view'''
    
    rule = get_object_or_404 (Rule, pk=ruleid)
    
    return direct_to_template (request, 'rule.html', {'rule': rule})

#===============================================================================
# ### add rule or condition ###
#===============================================================================

def add_new_condition(request, tmp_ruleid, ruleid=None):
    '''Add new condition view'''
        
    rid = int(tmp_ruleid)
    if rid is 0:
        
        tmp_rule = Rule.objects.filter (is_tmp=True)
        if len(tmp_rule) != 0:
            delete_rule_of_id (tmp_rule[0].pk)
            
        rule = Rule (is_tmp=True)
        rule.save()
        rid = rule.pk
            
    form = NewConditionForm ()
    
    ctx = {'form': form, 'tmp_ruleid': rid }
    if ruleid is not None:
        ctx['ruleid'] = ruleid
        
    return direct_to_template (request, 'condition_new.html', ctx)

def add_condition_to_rule(request, tmp_ruleid, ruleid=None):
    '''Creates condition type form and redirects to proper condition template'''
    
    if request.method == 'POST' and 'submit' in request.POST:
        
        condition_form = NewConditionForm(request.POST)
        if condition_form.is_valid():
            
            ctype = condition_form.cleaned_data['condition_types']
            cform = get_inside_condition_form(ctype)
            
            ctx = {'tmp_ruleid': tmp_ruleid, 'form': cform }
            if ruleid is not None:
                ctx['ruleid'] = ruleid
            
            conds_ctx = CONDITION_TYPES_D

            return direct_to_template (request, get_condition_template_file(ctype), 
                                       dict(ctx.items() + conds_ctx.items()) )
            
    return HttpResponseRedirect(reverse('filtr'))

def get_inside_condition (cond):
    ''' helper function: creates condition of specified type with condition=cond'''
    
    ctype = cond.ctype
    if int(ctype) == ATTACHMENT_C: 
        return AttachmentCondition.objects.get (condition=cond)  
    if int(ctype) == DATE_C:
        return DateCondition.objects.get (condition=cond)
    if int(ctype) == FROM_C:
        return AddressCondition.objects.get (condition=cond)
    if int(ctype) == ANR_C:
        return ANrCondition.objects.get (condition=cond)
    if int(ctype) == SIZE_C:
        return SizeCondition.objects.get (condition=cond)
    if int(ctype) == RESENT_C:
        return ResentCondition.objects.get (condition=cond)
    if int(ctype) == SUBJECT_C:
        return KeywordCondition.objects.get (condition=cond)
    if int(ctype) == TO_C:
        return AddressCondition.objects.get (condition=cond)
    if int(ctype) == KEYWORD_C:
        return KeywordCondition.objects.get (condition=cond)

def get_inside_condition_form (ctype):
    ''' helper function: creates form for condition of specified type (ctype)'''
    
    form = {ATTACHMENT_C: AttachmentConditionForm (),
            DATE_C: DateConditionForm (),
            FROM_C: FromConditionForm  (),
            ANR_C: ANrConditionForm (),
            SIZE_C: SizeConditionForm (),
            RESENT_C: ResentConditionForm (),
            SUBJECT_C: SubjectConditionForm (),
            TO_C: ToConditionForm (),
            KEYWORD_C: KeywordConditionForm (),
         }.get(int(ctype))
             
    return form

def get_inside_condition_form_of_instance (cond):
    ''' helper function: creates form for condition of specified type (ctype)'''
    
    ctype = cond.ctype
    spec_cond = get_inside_condition (cond)
    
    form = {ATTACHMENT_C: AttachmentConditionForm (instance=spec_cond),
            DATE_C: DateConditionForm (instance=spec_cond),
            FROM_C: FromConditionForm (instance=spec_cond),
            ANR_C: ANrConditionForm (instance=spec_cond),
            SIZE_C: SizeConditionForm (instance=spec_cond),
            RESENT_C: ResentConditionForm (instance=spec_cond),
            SUBJECT_C: SubjectConditionForm (instance=spec_cond),
            TO_C: ToConditionForm (instance=spec_cond),
            KEYWORD_C: KeywordConditionForm (instance=spec_cond),
         }.get(int(ctype))
             
    return form

def get_filled_inside_condition_form_of_instance (request, cond):
    ''' helper function: creates form for condition of specified type (ctype)'''
    
    ctype = cond.ctype
    spec_cond = get_inside_condition (cond)
    
    form = {ATTACHMENT_C: AttachmentConditionForm (request.POST, instance=spec_cond),
            DATE_C: DateConditionForm (request.POST, instance=spec_cond),
            FROM_C: FromConditionForm (request.POST, instance=spec_cond),
            ANR_C: ANrConditionForm (request.POST, instance=spec_cond),
            SIZE_C: SizeConditionForm (request.POST, instance=spec_cond),
            RESENT_C: ResentConditionForm (request.POST, instance=spec_cond),
            SUBJECT_C: SubjectConditionForm (request.POST, instance=spec_cond),
            TO_C: ToConditionForm (request.POST, instance=spec_cond),
            KEYWORD_C: KeywordConditionForm (request.POST, instance=spec_cond),
         }.get(int(ctype))
             
    return form

def get_condition_template_file (ctype):
    ''' helper function: returns template filename for condition of specified type (ctype)'''
    
    filename = {ATTACHMENT_C: "condition_attachment",
                DATE_C: "condition_date",
                FROM_C: "condition_from",
                SIZE_C: "condition_msg_size",
                ANR_C: "condition_msg_anr",
                SIZE_C: "condition_msg_size",
                RESENT_C: "condition_msg_resent",
                SUBJECT_C: "condition_subject",
                TO_C: "condition_to",
                KEYWORD_C: "condition_keyword",
             }.get(int(ctype), "")
             
    return filename + ".html"

def add_condition_attachment_to_rule(request, tmp_ruleid, ruleid=None):
    """ Checks attachment condition form validity, 
        adds it to rule (ruleid) 
        and redirects to rule view
    """
    
    if request.method == 'POST' and 'submit' in request.POST:
        
        ctype = ATTACHMENT_C
        aform = AttachmentConditionForm(request.POST)
        if aform.is_valid():
            
            #create condition
            rule = get_object_or_404 (Rule, pk=tmp_ruleid)
            cond = rule.conditions.create(ctype=ctype)
                
            #create attachment condition
            acond = AttachmentCondition(condition=cond)
            aform = AttachmentConditionForm(request.POST, instance=acond)
            aform.save()
            
            return redirect_to_init_rule_form (request, tmp_ruleid, ruleid)
            
        return redirect_to_init_condition_template (request, tmp_ruleid, ctype, aform, ruleid)

    return redirect_to_existing_rule_form (request, tmp_ruleid, ruleid)
           
def add_condition_date_to_rule(request, tmp_ruleid, ruleid=None):
    """ Checks date condition form validity, 
        adds it to rule (tmp_ruleid) 
        and redirects to rule view
    """
    
    if request.method == 'POST' and 'submit' in request.POST:
        
        ctype = DATE_C
        aform = DateConditionForm(request.POST)
        if aform.is_valid():
            
            #create condition
            rule = get_object_or_404 (Rule, pk=tmp_ruleid)
            cond = rule.conditions.create(ctype=ctype)
                
            #create attachment condition
            acond = DateCondition(condition=cond)
            aform = DateConditionForm(request.POST, instance=acond)
            aform.save()
            
            return redirect_to_init_rule_form (request, tmp_ruleid, ruleid)
            
        return redirect_to_init_condition_template (request, tmp_ruleid, ctype, aform, ruleid)

    return redirect_to_existing_rule_form (request, tmp_ruleid, ruleid)

def add_condition_from_to_rule(request, tmp_ruleid, ruleid=None):
    """ Checks from condition form validity, 
        adds it to rule (tmp_ruleid) 
        and redirects to rule view
    """
    
    if request.method == 'POST' and 'submit' in request.POST:
        
        ctype = FROM_C
        aform = FromConditionForm(request.POST)
        if aform.is_valid():
            
            #create condition
            rule = get_object_or_404 (Rule, pk=tmp_ruleid)
            cond = rule.conditions.create(ctype=ctype)
                
            #create attachment condition
            acond = AddressCondition(condition=cond)
            acond.type = FROM_C
            aform = FromConditionForm(request.POST, instance=acond)
            aform.save()
            
            return redirect_to_init_rule_form (request, tmp_ruleid, ruleid)
            
        return redirect_to_init_condition_template (request, tmp_ruleid, ctype, aform, ruleid)

    return redirect_to_existing_rule_form (request, tmp_ruleid, ruleid)

def add_condition_keyword_to_rule(request, tmp_ruleid, ruleid=None):
    """ Checks keyword condition form validity, 
        adds it to rule (tmp_ruleid) 
        and redirects to rule view
    """
    
    if request.method == 'POST' and 'submit' in request.POST:
        
        ctype = KEYWORD_C
        aform = KeywordConditionForm(request.POST)
        if aform.is_valid():
            
            #create condition
            rule = get_object_or_404 (Rule, pk=tmp_ruleid)
            cond = rule.conditions.create(ctype=ctype)
                
            #create attachment condition
            acond = KeywordCondition(condition=cond)
            aform = KeywordConditionForm(request.POST, instance=acond)
            aform.save()
            
            return redirect_to_init_rule_form (request, tmp_ruleid, ruleid)
            
        return redirect_to_init_condition_template (request, tmp_ruleid, ctype, aform, ruleid)

    return redirect_to_existing_rule_form (request, tmp_ruleid, ruleid)

def add_condition_anr_to_rule(request, tmp_ruleid, ruleid=None):
    """ Checks attachment number condition form validity, 
        adds it to rule (tmp_ruleid) 
        and redirects to rule view
    """
    
    if request.method == 'POST' and 'submit' in request.POST:
        
        ctype = ANR_C
        aform = ANrConditionForm(request.POST)
        if aform.is_valid():
            
            #create condition
            rule = get_object_or_404 (Rule, pk=tmp_ruleid)
            cond = rule.conditions.create(ctype=ctype)
                
            #create attachment condition
            acond = ANrCondition(condition=cond)
            acond.type = TO_C
            aform = ANrConditionForm(request.POST, instance=acond)
            aform.save()
            
            return redirect_to_init_rule_form (request, tmp_ruleid, ruleid)
            
        return redirect_to_init_condition_template (request, tmp_ruleid, ctype, aform, ruleid)

    return redirect_to_existing_rule_form (request, tmp_ruleid, ruleid)
    
def add_condition_resent_to_rule(request, tmp_ruleid, ruleid=None):
    """ Checks resent condition form validity, 
        adds it to rule (tmp_ruleid) 
        and redirects to rule view
    """
    
    if request.method == 'POST' and 'submit' in request.POST:
        
        ctype = RESENT_C
        aform = ResentConditionForm(request.POST)
        if aform.is_valid():
            
            #create condition
            rule = get_object_or_404 (Rule, pk=tmp_ruleid)
            cond = rule.conditions.create(ctype=ctype)
                
            #create attachment condition
            acond = ResentCondition(condition=cond)
            aform = ResentConditionForm(request.POST, instance=acond)
            aform.save()
            
            return redirect_to_init_rule_form (request, tmp_ruleid, ruleid)
            
        return redirect_to_init_condition_template (request, tmp_ruleid, ctype, aform, ruleid)

    return redirect_to_existing_rule_form (request, tmp_ruleid, ruleid)
    
def add_condition_size_to_rule(request, tmp_ruleid, ruleid=None):
    """ Checks size condition form validity, 
        adds it to rule (tmp_ruleid) 
        and redirects to rule view
    """
    
    if request.method == 'POST' and 'submit' in request.POST:
        
        ctype = SIZE_C
        aform = SizeConditionForm(request.POST)
        if aform.is_valid():
            
            #create condition
            rule = get_object_or_404 (Rule, pk=tmp_ruleid)
            cond = rule.conditions.create(ctype=ctype)
                
            #create attachment condition
            acond = SizeCondition(condition=cond)
            aform = SizeConditionForm(request.POST, instance=acond)
            aform.save()
            
            return redirect_to_init_rule_form (request, tmp_ruleid, ruleid)
            
        return redirect_to_init_condition_template (request, tmp_ruleid, ctype, aform, ruleid)

    return redirect_to_existing_rule_form (request, tmp_ruleid, ruleid)
    
def add_condition_subject_to_rule(request,tmp_ruleid, ruleid=None):
    """ Checks subject condition form validity, 
        adds it to rule (tmp_ruleid) 
        and redirects to rule view
    """
    
    if request.method == 'POST' and 'submit' in request.POST:
        
        ctype = SUBJECT_C
        aform = SubjectConditionForm(request.POST)
        if aform.is_valid():
            
            #create condition
            rule = get_object_or_404 (Rule, pk=tmp_ruleid)
            cond = rule.conditions.create(ctype=ctype)
                
            #create attachment condition
            acond = KeywordCondition(condition=cond)
            acond.keyword_range = SUBJECT_R
            acond.how_many = 1
            acond.how_many_operator = EQ_O
            acond.keyword = aform.cleaned_data['keyword']
            acond.keyword_operator = aform.cleaned_data['keyword_operator']
            acond.save()
            
            return redirect_to_init_rule_form (request, tmp_ruleid, ruleid)
            
        return redirect_to_init_condition_template (request, tmp_ruleid, ctype, aform, ruleid)

    return redirect_to_existing_rule_form (request, tmp_ruleid, ruleid)
    
def add_condition_to_to_rule(request,tmp_ruleid, ruleid=None):
    """ Checks to condition form validity, 
        adds it to rule (tmp_ruleid) 
        and redirects to rule view
    """
    
    if request.method == 'POST' and 'submit' in request.POST:
        
        ctype = TO_C
        aform = ToConditionForm(request.POST)
        if aform.is_valid():
            
            #create condition
            rule = get_object_or_404 (Rule, pk=tmp_ruleid)
            cond = rule.conditions.create(ctype=ctype)
                
            #create attachment condition
            acond = AddressCondition(condition=cond)
            acond.type = TO_C
            aform = ToConditionForm(request.POST, instance=acond)
            aform.save()
            
            return redirect_to_init_rule_form (request, tmp_ruleid, ruleid)
            
        return redirect_to_init_condition_template (request, tmp_ruleid, ctype, aform, ruleid)

    return redirect_to_existing_rule_form (request, tmp_ruleid, ruleid)
    
#===============================================================================
# ### edit condition ###
#===============================================================================

def confirm_condition (request, tmp_ruleid, ctype, condid=None, ruleid=None):
    '''Saves condition an redirects to rule form template'''
    
    if condid is None or len(condid) == 0:
        return add_base_condition (request, tmp_ruleid, ctype)
    
    cond = get_object_or_404 (Condition, pk=condid)
    cform = get_filled_inside_condition_form_of_instance (request, cond)
    
    if request.method == 'POST' and 'submit' in request.POST:
        
        if cform.is_valid():
                            
            cform.save()
            return redirect_to_existing_rule_form (request, tmp_ruleid, ruleid)
            
        return redirect_to_existing_condition_template (request, tmp_ruleid, condid, ruleid)
        
    return redirect_to_existing_rule_form (request, tmp_ruleid, ruleid)

def add_base_condition (request, ruleid, ctype):
    ''' helper function: redirects to add condition of specific type method'''
    
    if int(ctype) == ATTACHMENT_C: 
        return add_condition_attachment_to_rule (request, ruleid)
    if int(ctype) == DATE_C:
        return add_condition_date_to_rule (request, ruleid)
    if int(ctype) == FROM_C:
        return add_condition_from_to_rule (request, ruleid)
    if int(ctype) == ANR_C:
        return add_condition_anr_to_rule (request, ruleid)
    if int(ctype) == SIZE_C:
        return add_condition_size_to_rule (request, ruleid)
    if int(ctype) == RESENT_C:
        return add_condition_resent_to_rule (request, ruleid)
    if int(ctype) == SUBJECT_C:
        return add_condition_subject_to_rule (request, ruleid)
    if int(ctype) == TO_C:
        return add_condition_to_to_rule (request, ruleid)
    if int(ctype) == KEYWORD_C:
        return add_condition_keyword_to_rule (request, ruleid)
    
def edit_condition (request, tmp_ruleid, condid, ruleid=None):
    '''Redirects to proper condition form'''
    
    return redirect_to_existing_condition_template (request, tmp_ruleid, condid, ruleid)
    
def delete_condition (request, tmp_ruleid, condid, ruleid=None):
    '''Deletes rule condition and redirects to rule view'''
    
    if request.method == 'GET':
        
        cond = get_object_or_404 (Condition, pk=condid)
        cond.delete()
        
    return redirect_to_existing_rule_form (request, tmp_ruleid, ruleid)        

#===============================================================================
# ### edit rule ###
#===============================================================================

def confirm_rule(request, tmp_ruleid, ruleid=None):
    '''Checks rule form validity, adds it to rules and redirects to rules view'''
    
    if request.method == 'POST':
        
        if 'submit' in request.POST:
            
            #usun stara regule, dodaj tymczasowa
            rule = get_object_or_404 (Rule, pk=tmp_ruleid)
            form = RuleForm (0, request.POST, instance=rule)

            if 'expression' in request.POST:
                expression = request.POST.get('expression')
                form.expression = expression
                
            if form.is_valid():
                rule.is_tmp = False
                rule.save()
                form.save()
                
                if ruleid is not None and len(ruleid) != 0:
                    delete_rule_of_id (ruleid)
                                        
                return HttpResponseRedirect (reverse('filtr'))
    
            return redirect_to_existing_rule_form (request, tmp_ruleid, ruleid)
        
        elif 'cancel' in request.POST:
            
            # usun tymczasowa regule, zostaw stara
            delete_rule_of_id (tmp_ruleid)
            return HttpResponseRedirect (reverse('filtr'))
    
    return HttpResponseRedirect(reverse('filtr'))

def edit_rule(request, ruleid):
    '''Redirects to rule form view'''
    
    # 1. kopia reguly
    tmp_rules = Rule.objects.filter(is_tmp=True)
    if len(tmp_rules) > 0:
        delete_rule_of_id(tmp_rules[0].pk)
    
    rule = get_object_or_404 (Rule, pk=ruleid)
    tmp_rule = copy.deepcopy (rule)
    tmp_rule.pk = None
    tmp_rule.is_tmp = True

    # 2. kopia tabeli regula-warunki
    conds = rule.conditions.all()
    for cond in conds:
        tmp_cond = copy.deepcopy (cond)
        tmp_cond.pk = None
        tmp_cond.save()

        #3. kopia konkretnego warunku
        ctype = cond.ctype
        spec_cond = None
        if ctype == ATTACHMENT_C:
            spec_cond = AttachmentCondition.objects.get (condition=cond)
        elif ctype == DATE_C:
            spec_cond = DateCondition.objects.get (condition=cond)
        elif ctype == FROM_C or ctype == TO_C :
            spec_cond = AddressCondition.objects.get (condition=cond)
        elif ctype == KEYWORD_C or ctype == SUBJECT_C :
            spec_cond = KeywordCondition.objects.get (condition=cond)
        elif ctype == ANR_C:
            spec_cond = ANrCondition.objects.get (condition=cond)
        elif ctype == SIZE_C:
            spec_cond = SizeCondition.objects.get (condition=cond)
        elif ctype == RESENT_C:
            spec_cond = ResentCondition.objects.get (condition=cond)
                        
        tmp_spec_cond = copy.deepcopy(spec_cond)
        tmp_spec_cond.condition = tmp_cond
        tmp_spec_cond.save()
            
        tmp_rule.save()
        tmp_rule.conditions.add(tmp_cond)
        
    tmp_rule.save()
        
    return redirect_to_existing_rule_form (request, tmp_rule.pk, ruleid)
    
#===============================================================================
# ### delete rule ###
#===============================================================================

def delete_rule(request, ruleid):
    '''Deletes rule and redirects to rules view'''
    
    if request.method == 'GET':
        delete_rule_of_id (ruleid)
                
    return HttpResponseRedirect(reverse('filtr'))

def delete_rule_of_id (ruleid):
    '''Deletes rule'''
    
    rule = get_object_or_404 (Rule, pk=ruleid)
    if rule:
        conditions = rule.conditions.all()
        for cond in conditions:
            cond.delete()
        rule.delete()

#===============================================================================
# ### helpers ###
#===============================================================================

def redirect_to_init_rule_form (request, tmp_ruleid, ruleid):
    
    rule = get_object_or_404 (Rule, pk=tmp_ruleid)
    conds_nr = rule.conditions.count()
    
    return redirect_to_rule_form (request, rule, conds_nr, ruleid)
    
def redirect_to_existing_rule_form (request, tmp_ruleid, ruleid):
    
    rule = get_object_or_404 (Rule, pk=tmp_ruleid)
    if len(rule.conditions.all()) > 0:
        # 0 means that rule form should not construct its own expression string
        return redirect_to_rule_form (request, rule, 0, ruleid)
    else:
        return HttpResponseRedirect(reverse('filtr'))
    
    rule = get_object_or_404 (Rule, pk=ruleid)
    rule.delete()
    return HttpResponseRedirect(reverse('filtr'))

def redirect_to_rule_form (request, rule, conds_nr=0, ruleid=None):
        
    rform = RuleForm (conds_nr, instance=rule)
            
    ctx_dict = { 'rule': rule, 'form': rform }
    if ruleid is not None:
        ctx_dict['ruleid'] = ruleid
        
    conds_dict = CONDITION_TYPES_D
    return direct_to_template (request, 'rule_form.html', 
                               dict(ctx_dict.items() + conds_dict.items()) )
 

def redirect_to_init_condition_template (request, tmp_ruleid, ctype, cform, ruleid):
    
    ctx = { 'form': cform, 'tmp_ruleid': tmp_ruleid }
    if ruleid is not None:
        ctx['ruleid'] = ruleid
    conds_ctx = CONDITION_TYPES_D

    return direct_to_template (request, get_condition_template_file (ctype), 
                               dict (ctx.items() + conds_ctx.items()))

def redirect_to_existing_condition_template (request, tmp_ruleid, condid, ruleid):
    
    cond = get_object_or_404 (Condition, pk=condid)
    cform = get_inside_condition_form_of_instance(cond)
    ctype = cond.ctype
    
    ctx = { 'form': cform, 'tmp_ruleid': tmp_ruleid, 'condid': condid }
    if ruleid is not None:
        ctx['ruleid'] = ruleid
    conds_ctx = CONDITION_TYPES_D

    return direct_to_template (request, get_condition_template_file (ctype), 
                               dict (ctx.items() + conds_ctx.items()))
    